/*
 * <<
 *  Davinci
 *  ==
 *  Copyright (C) 2016 - 2019 EDP
 *  ==
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *        http://www.apache.org/licenses/LICENSE-2.0
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *  >>
 *
 */

package edp.core.utils;

import static edp.core.consts.Consts.PATTERN_EMAIL_FORMAT;
import static edp.davinci.core.common.Constants.EMAIL_DEFAULT_TEMPLATE;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import com.alibaba.druid.util.StringUtils;
import com.google.common.base.Stopwatch;

import edp.core.exception.ServerException;
import edp.core.model.MailContent;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MailUtils
{
    
    @Autowired
    private JavaMailSender javaMailSender;
    
    @Autowired
    private TemplateEngine templateEngine;
    
    @Value("${spring.mail.username}")
    private String mailUsername;
    
    @Value("${spring.mail.fromAddress:}")
    private String fromAddress;
    
    @Value("${spring.mail.nickname}")
    private String nickName;
    
    private static final String MAIL_TEXT_KEY = "text";
    
    private static final String MAIL_HTML_KEY = "html";
    
    public void sendMail(MailContent mailContent, Logger customLogger)
        throws ServerException
    {
        Stopwatch watch = Stopwatch.createStarted();
        if (mailContent == null)
        {
            throw new ServerException("Mail content is null");
        }
        
        String from = StringUtils.isEmpty(fromAddress) ? mailUsername : fromAddress;
        
        String displayName = nickName;
        if (!StringUtils.isEmpty(mailContent.getFrom()))
        {
            Matcher matcher = PATTERN_EMAIL_FORMAT.matcher(mailContent.getFrom());
            if (!matcher.find())
            {
                log.error("Unknown email sending address: {}", mailContent.getFrom());
                if (customLogger != null)
                {
                    customLogger.error("Unknown email sending address: {}", mailContent.getFrom());
                }
                throw new ServerException("Unknown email sending address: " + mailContent.getFrom());
            }
            from = mailContent.getFrom();
        }
        
        if (!StringUtils.isEmpty(mailContent.getNickName()))
        {
            displayName = mailContent.getNickName();
        }
        
        if (StringUtils.isEmpty(mailContent.getSubject()))
        {
            log.error("Email subject cannot be EMPTY");
            if (customLogger != null)
            {
                customLogger.error("Email subject cannot be EMPTY");
            }
            throw new ServerException("Email subject cannot be EMPTY");
        }
        
        if (null == mailContent.getTo() || mailContent.getTo().length < 1)
        {
            log.error("Email receiving address(to) cannot be EMPTY");
            if (customLogger != null)
            {
                log.error("Email receiving address(to) cannot be EMPTY");
            }
            throw new ServerException("Email receiving address cannot be EMPTY");
        }
        
        boolean multipart = false;
        boolean emptyAttachments = CollectionUtils.isEmpty(mailContent.getAttachments());
        String mailContentTemplate = null;
        String contentHtml = null;
        Context context = new Context();
        switch (mailContent.getMailContentType())
        {
            case TEXT:
                if (StringUtils.isEmpty(mailContent.getContent()) && emptyAttachments)
                {
                    throw new ServerException("Mail content cannot be EMPTY");
                }
                if (!emptyAttachments)
                {
                    multipart = true;
                }
                context.setVariable(MAIL_TEXT_KEY, mailContent.getContent());
                mailContentTemplate = EMAIL_DEFAULT_TEMPLATE;
                break;
            case HTML:
                if (StringUtils.isEmpty(mailContent.getHtmlContent()) && emptyAttachments)
                {
                    throw new ServerException("Mail content cannot be EMPTY");
                }
                if (!emptyAttachments)
                {
                    multipart = true;
                }
                context.setVariable(MAIL_HTML_KEY, mailContent.getHtmlContent());
                mailContentTemplate = EMAIL_DEFAULT_TEMPLATE;
                break;
            case TEMPLATE:
                if (StringUtils.isEmpty(mailContent.getTemplate()) && emptyAttachments)
                {
                    throw new ServerException("Mail content cannot be EMPTY");
                }
                if (!CollectionUtils.isEmpty(mailContent.getTemplateContent()))
                {
                    mailContent.getTemplateContent().forEach(context::setVariable);
                }
                mailContentTemplate = mailContent.getTemplate();
                multipart = true;
                break;
        }
        
        try
        {
            MimeMessage message = javaMailSender.createMimeMessage();
            MimeMessageHelper messageHelper = new MimeMessageHelper(message, multipart);
            
            messageHelper.setFrom(from, displayName);
            messageHelper.setSubject(mailContent.getSubject());
            messageHelper.setTo(mailContent.getTo());
            if (null != mailContent.getCc() && mailContent.getCc().length > 0)
            {
                messageHelper.setCc(mailContent.getCc());
            }
            if (null != mailContent.getBcc() && mailContent.getBcc().length > 0)
            {
                messageHelper.setBcc(mailContent.getBcc());
            }
            
            List<String> imageContentIds = new ArrayList<>();
            
            if (!emptyAttachments)
            {
                mailContent.getAttachments().forEach(attachment -> {
                    if (attachment.isImage())
                    {
                        imageContentIds.add(attachment.getName());
                    }
                });
            }
            
            if (!CollectionUtils.isEmpty(imageContentIds))
            {
                context.setVariable("images", imageContentIds);
            }
            
            contentHtml = templateEngine.process(mailContentTemplate, context);
            messageHelper.setText(contentHtml, true);
            
            if (!emptyAttachments)
            {
                mailContent.getAttachments().forEach(attachment -> {
                    try
                    {
                        if (attachment.isImage())
                        {
                            messageHelper.addInline(attachment.getName(), attachment.getFile());
                        }
                        else
                        {
                            messageHelper.addAttachment(attachment.getName(), attachment.getFile());
                        }
                    }
                    catch (MessagingException e)
                    {
                        log.warn(e.getMessage());
                        if (customLogger != null)
                        {
                            log.warn(e.getMessage());
                        }
                    }
                });
            }
            
//            javaMailSender.send(message);
            log.info("Email sending --- content: {}, cost: {}", mailContent.toString(), watch.elapsed(TimeUnit.MILLISECONDS));
            if (customLogger != null)
            {
                customLogger.info("Email sending --- content: {}, cost: {}", mailContent.toString(), watch.elapsed(TimeUnit.MILLISECONDS));
            }
        }
        catch (MessagingException e)
        {
            log.error("Send mail failed, {}\n", e.getMessage());
            if (customLogger != null)
            {
                customLogger.error("Send mail failed, {}\n", e.getMessage());
            }
            e.printStackTrace();
            throw new ServerException(e.getMessage());
        }
        catch (UnsupportedEncodingException e)
        {
            log.error("Send mail failed, {}\n", e.getMessage());
            if (customLogger != null)
            {
                customLogger.error("Send mail failed, {}\n", e.getMessage());
            }
            e.printStackTrace();
        }
    }
}
